﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using Microsoft.LiveFX.Client;
using Microsoft.LiveFX.ResourceModel;  // For RoleType


namespace a_fung
{
	public partial class Form1 : Form
	{
		LiveOperatingEnvironment env = new LiveOperatingEnvironment();
		Mesh mesh = null;

		const string LIVE_MESH_FOLDER = "LiveMeshFolder";
		const string LIVE_MESH_FILES = "LiveMeshFiles";
		const string FILE_HANDLER_TYPE = "FileSystem";
		const string DEFAULT_RATING = "Okay";

		const string NONE = "-- none --";

		MeshObject theMeshObject = null;
		DataFeed theDataFeed = null;

		// Name of file to add and stream to file
		string fileAndPath;
		Stream filestream;

		// Name of temp file
		string tempFile;

		// Stream for temp pic
		FileStream picStream;


		public Form1()
		{
			InitializeComponent();
			this.FormClosing += new FormClosingEventHandler(Form1_FormClosing);
		}

		void Form1_FormClosing(object sender, FormClosingEventArgs e)
		{
			// Clear the PictureBox control instance.
			ShowPictureBox.Image = null;

			// If temp file exists, delete it
			if (!string.IsNullOrEmpty(tempFile))
			{
				try
				{
					GC.Collect();
					GC.WaitForPendingFinalizers();
					File.Delete(tempFile);
				}
				catch (Exception ex)
				{
					MessageBox.Show("Caught expection trying to delete " + tempFile +
					   Environment.NewLine + "   " + ex.Message +
					   Environment.NewLine + "You must delete it manually");
				}
			}

		}

		private void ConnectButton_Click(object sender, EventArgs e)
		{
			if (mesh != null)
			{
				return;
			}

			LiveItemAccessOptions accessOptions = new LiveItemAccessOptions(true);

			try
			{
				//*
				string address = LiveIdTextBox.Text;

				if (string.IsNullOrEmpty(address))
				{
					MessageBox.Show("You must specify a Windows Live ID", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				string password = PasswordTextBox.Text;

				if (string.IsNullOrEmpty(password))
				{
					MessageBox.Show("You must enter your password", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}
				///*/

				string uri = Properties.Resources.Uri;

				if (string.IsNullOrEmpty(uri))
				{
					MessageBox.Show("No URI in the resources file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}
				// Create user token
				String token = new NetworkCredential(address, password, uri).GetWindowsLiveAuthenticationToken();
				//String token = "dD1Fd0RnQVdyM0F3QVUzU1FZRzlZQ3ZBalNJRlVjZ1dlenE2eC9qanFBQUQ2WkhmU3lVK3dGczQ4aDdJQUc2K2dsWW5lNEtFZ1NoZTVwUzFFNlRVZzhLMEdjb3h5RWpKTmZCVDc5cXFkanZkZVhCMmhwdmdnYlpJS1kvRHR6R0IxWWN6SCsxUkVyOGx2ZHVMaU1WMzVJZWJkaC9Lc1h6WjMwSHBRYXlDYURlbE9Rc2lVVVQ1eU9PTkxYZnZqcnltT2VYTG9SV1JjS2JSTW8rd0ZpcFZsbUEyWUFBQWlQT1dkbG1pdzJMekFCb0VWRTJRenVpTWVpWk9kaDFvZHd4RXhLSnlhV3Z5eWVMc3htTm16ZmxJYllneUQ0dHhKeVJoZ1AxME1xYVFrRkk2cFNiVjBkSEp4OHF0SjlRZ0FlWStmVENPM0F3eEZaNEhPNzJUK29LSzQySmZpbTVRNTFuc3hqQ1RqSjl0Q1dlZU5MSFNpOWhFVnplQ1kzVzBSTUZZVlRwRy9ZdEFVZUV3SHl6TEhzYzFNaGplcUFJdnUxRFIvWG9BOUw5ek1SRVl0SktCNmpIVE1YT25OZjk4akhXWmRsdU9NVVpHMloyaVcvSmlVRjA5MFAxK29ibTRHU200RjlpQmtKc3orTE5VZFAzQnRzSFM1MFJHVUtxaTVHQ3REY25yaGc4NVhZZTdmdlViQm0wK2hFMVcyUUxkTjV5VmdneGZXbDJCTW14bEZ4OFA5RXlYTm9HSG93c3p3bDMzVEZoUHFLK2VLUkJjaVNpMXpINlFudE5lTzZOMDN5aGRtYjRKS1JjTUo1cUNFUTFCd1BjSXc0NGw5bGRwNmdQME1CJnA9";

				// Create URI for cloud Mesh
				Uri theUri = new Uri(uri);

				env.Connect(token, AuthenticationTokenType.UserToken, theUri, accessOptions);

				mesh = env.Mesh;

				// Tell user they are connected
				ConnectButton.Text = "connected";

				ShowMeshObjects();
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception trying to connect: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		void ShowMeshObjects()
		{
			if (mesh == null)
			{
				MessageBox.Show("You must connect to see MeshObjects", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			try
			{
				MeshObjectListBox.Items.Clear();

				// Get all of the MeshObjects
				var meshObjects = (from meshObject in mesh.CreateQuery<MeshObject>().Execute()
								   select meshObject);

				// If we don't have any mesh objects,
				// we have nothing to display
				if (meshObjects.Count() == 0)
				{
					MeshObjectListBox.Items.Add(NONE);
					return;
				}

				// Display all of the mesh objects
				foreach (MeshObject meshObject in meshObjects)
				{
					// Add MeshObject title to list
					MeshObjectListBox.Items.Add(meshObject.Resource.Title);
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception listing Mesh objects: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}
		}

		MeshObject GetMeshObjectByTitle(string title)
		{
			MeshObject meshObject = (from mo in mesh.CreateQuery<MeshObject>()
									 where mo.Resource.Title == title
									 select mo).FirstOrDefault<MeshObject>();

			return meshObject;
		}

		private void CreateButton_Click(object sender, EventArgs e)
		{

			// Return if not connected
			if (mesh == null)
			{
				MessageBox.Show("You must connect before you can add a new Mesh object", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			try
			{
				// Get name of new Mesh object
				if (string.IsNullOrEmpty(NewNameTextBox.Text))
				{
					MessageBox.Show("You must supply a name for the new Mesh object", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				string meshObjectName = NewNameTextBox.Text;

				// See if a Mesh object by that name already exists
				MeshObject meshObject = GetMeshObjectByTitle(meshObjectName);

				if (meshObject != null)
				{
					MessageBox.Show("Sorry, that Mesh object already exists", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				// Create Mesh object
				theMeshObject = new MeshObject(meshObjectName);

				// Set its type to Mesh folder
				theMeshObject.Resource.Type = LIVE_MESH_FOLDER;

				// Add new Mesh object to collection
				mesh.MeshObjects.Add(ref theMeshObject);

				// Create DataFeed for files
				theDataFeed = new DataFeed(LIVE_MESH_FILES);

				// Set type and handler type
				theDataFeed.Resource.Type = LIVE_MESH_FILES;
				theDataFeed.Resource.HandlerType = FILE_HANDLER_TYPE;

				// Add new data feed to collection
				theMeshObject.DataFeeds.Add(ref theDataFeed);

				// Clear Mesh object name
				NewNameTextBox.Text = "";

				// Tell the user they were successful creating the Mesh object
				MessageBox.Show("Congratulations. You created the Mesh object: " + meshObjectName);

				ShowMeshObjects();
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception trying to create a new Mesh object: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}

		}


		DataFeed GetFileDataFeed(MeshObject meshObject)
		{
			DataFeed theDataFeed = (from dataFeed in meshObject.CreateQuery<DataFeed>()
									where dataFeed.Resource.Title == LIVE_MESH_FILES
									select dataFeed).FirstOrDefault<DataFeed>();

			return theDataFeed;
		}

		private void MeshObjectListBox_SelectedIndexChanged(object sender, EventArgs e)
		{
			// Get title of selected Mesh object
			string meshObjectTitle = MeshObjectListBox.SelectedItem.ToString();

			// Get the associated MeshObject and cache it
			theMeshObject = GetMeshObjectByTitle(meshObjectTitle);
			// If it has a DataFeed for files, cache that
			theDataFeed = GetFileDataFeed(theMeshObject);
		}

		void ShowResources()
		{
			// Return if not connected
			if (mesh == null)
			{
				MessageBox.Show("You must connect before you can show MeshObject Resources", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// Return if no Mesh object selected
			if (theMeshObject == null)
			{
				MessageBox.Show("You must select a Mesh object before you can see its resources", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// Clear listbox
			ResourceListBox.Items.Clear();

			// Show files
			ResourceListBox.Items.Add("Files:");

			DataFeed theDataFeed = GetFileDataFeed(theMeshObject);

			if (theDataFeed == null)
			{
				ResourceListBox.Items.Add("   " + NONE);
			}
			else
			{
				var dataEntries = (from dataEntry in theDataFeed.CreateQuery<DataEntry>().Execute()
								   select dataEntry);

				if (dataEntries.Count() == 0)
				{
					ResourceListBox.Items.Add("   " + NONE);
				}
				else
				{
					foreach (DataEntry dataEntry in dataEntries)
					{
						// Show file name
						ResourceListBox.Items.Add("   " + dataEntry.Resource.Title);
					}
				}
			}

			// Put a blank line between resource categories
			ResourceListBox.Items.Add("");

			// Show mappings
			ResourceListBox.Items.Add("Mappings:");

			var mappings = (from mapping in theMeshObject.CreateQuery<Mapping>().Execute()
							select mapping);

			if (mappings.Count() == 0)
			{
				ResourceListBox.Items.Add("   " + NONE);
			}
			else
			{
				foreach (Mapping mapping in mappings)
				{
					// If no datafeed mappings, no mappings!!!
					if (mapping.Resource.DataFeedMappings.Count() > 0)
					{
						// Get local folder name
						string localMap = mapping.Resource.DataFeedMappings.ElementAt(0).Value.ToString();

						// Get device name
						string device = mapping.Device.Resource.Title;

						// Add to list
						ResourceListBox.Items.Add("   " + localMap + " on device " + device);
					}
					else
					{
						ResourceListBox.Items.Add("   " + NONE);
					}
				}
			}

			// Put a blank line between resource categories
			ResourceListBox.Items.Add("");

			// Show members
			ResourceListBox.Items.Add("Members:");

			var members = (from member in theMeshObject.CreateQuery<Member>().Execute()
						   select member);

			if (members.Count() == 0)
			{
				ResourceListBox.Items.Add("   " + NONE);
			}
			else
			{
				foreach (Member member in members)
				{
					string title = member.Resource.Title;
					string email = member.Resource.Email;

					string entry = "   " + "Name: " + title + ", " + "Email address:  " + email;

					if (!member.Resource.InvitationAccepted)
					{
						entry += " (pending)";
					}

					ResourceListBox.Items.Add(entry);
				}
			}
		}

		private void ShowResourcesButton_Click(object sender, EventArgs e)
		{
			ShowResources();
		}

		bool IsGraphicsFile(string filename)
		{
			// Get extension
			int length = filename.Length;
			string lastThreeChars = filename.Substring(length - 3, 3).ToUpper();

			if (lastThreeChars == "BMP" || lastThreeChars == "JPG" || lastThreeChars == "GIF")
			{
				return true;
			}

			return false;
		}

		void ShowPic(string fullFileAndPathname)
		{
			// Clear the PictureBox control instance.
			ShowPictureBox.Image = null;
			Bitmap MyImage = new Bitmap(fullFileAndPathname);

			// Center image and clip if too large
			ShowPictureBox.SizeMode = PictureBoxSizeMode.CenterImage;
			ShowPictureBox.Image = (Image)MyImage;
		}

		private void BrowseButton_Click(object sender, EventArgs e)
		{
			// Return if not connected
			if (mesh == null)
			{
				MessageBox.Show("You must connect before you can browse", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// Return if no Mesh object selected
			if (theMeshObject == null)
			{
				MessageBox.Show("You must select a Mesh object", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			try
			{
				// Browse for file
				openFileDialog1.InitialDirectory = "C:\\";
				openFileDialog1.Filter = "Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*";
				openFileDialog1.ShowDialog();

				// Cache filestream and fully-qualified filename
				filestream = openFileDialog1.OpenFile();
				fileAndPath = openFileDialog1.FileName;

				// Show file in PictureBox
				ShowPic(fileAndPath);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception browsing for file: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}

		}

		private void AddPixButton_Click(object sender, EventArgs e)
		{

			try
			{
				// Make sure user has set a rating
				if (AddRatingListBox.SelectedItems.Count == 0)
				{
					MessageBox.Show("You must select a rating", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				if (string.IsNullOrEmpty(fileAndPath))
				{
					MessageBox.Show("Please browse and select a file", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
					return;
				}

				// Get rating from list box
				Ratings theRating = new Ratings();

				theRating.picRating = AddRatingListBox.SelectedItem.ToString();

				// Get just the name of the file
				int lastSlashIndex = fileAndPath.LastIndexOf("\\");
				string filename = fileAndPath.Substring(lastSlashIndex + 1, fileAndPath.Length - lastSlashIndex - 1);

				DataEntry dataEntry = theDataFeed.DataEntries.Add(filestream, filename, null);

				// Add user data (ratings) to data entry
				dataEntry.Resource.SetUserData<Ratings>(theRating);

				// Required to see user data on all devices/Live Desktop/Data Model Browser
				dataEntry.Update();

				// Make sure everyone is synchronized
				theDataFeed.SyncEntries.Synchronize();
				theDataFeed.Update();

				// Clear picture box image
				ShowPictureBox.Image = null;

				// Unselect rating
				AddRatingListBox.SelectedItem = null;

				// Clear file and path
				fileAndPath = "";

				// Tell user they added the file
				MessageBox.Show("Congratulations, you added the file " + filename);
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught Exception adding a picture: " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
			}

		}

		private void FindPixButton_Click(object sender, EventArgs e)
		{
			// Return if not connected
			if (mesh == null)
			{
				MessageBox.Show("You must connect", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			string findText = null;

			if (!string.IsNullOrEmpty(FindPixTextBox.Text))
			{
				findText = FindPixTextBox.Text.ToLower();
			}

			string selectedItem = null;

			if (FindRatingListBox.SelectedItems.Count != 0)
			{
				selectedItem = FindRatingListBox.SelectedItem.ToString();
			}

			// If text box empty and no rating selected, do nothing
			if (findText == null && selectedItem == null)
			{
				MessageBox.Show("You must enter some text in the text box or select a rating", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// Clear picture box image
			ShowPictureBox.Image = null;

			// Clear out results list box
			FindPixListBox.Items.Clear();

			string filename;
			Ratings theRating;
			string rating;

			// Search all Mesh objects for files
			var meshObjects = (from meshObject in mesh.CreateQuery<MeshObject>()
							   where meshObject.Resource.Type == LIVE_MESH_FOLDER
							   select meshObject);

			foreach (MeshObject meshObject in meshObjects)
			{
				DataFeed dataFeed = GetFileDataFeed(meshObject);

				if (dataFeed == null)
				{
					continue;
				}

				var dataEntries = (from dataEntry in dataFeed.CreateQuery<DataEntry>()
								   select dataEntry);

				foreach (DataEntry dataEntry in dataEntries)
				{
					filename = dataEntry.Resource.Title;
					theRating = dataEntry.Resource.GetUserData<Ratings>();

					if (theRating != null)
					{
						rating = theRating.picRating;
					}
					else
					{
						rating = DEFAULT_RATING;
					}

					// Did they search by name?
					if (findText != null)
					{
						if (filename.ToLower().Contains(findText))
						{
							// The file was found, so did they also search by rating?
							if (selectedItem != null)
							{
								if (selectedItem == rating)
								{
									// Make sure it is a graphics file
									if (IsGraphicsFile(filename))
									{
										// Add the file name to the list box
										FindPixListBox.Items.Add(filename);
									}
								}
							}
							else
							{
								// Make sure it is a graphics file
								if (IsGraphicsFile(filename))
								{
									// They did not also search by rating,
									// so add the file name to the list box
									FindPixListBox.Items.Add(filename);
								}
							}
						}
					}
					else
					{
						// Did not want to search by name, so it must be by rating
						if (selectedItem == rating)
						{
							// Make sure it is a graphics file
							if (IsGraphicsFile(filename))
							{
								// Add the file name to the list box
								FindPixListBox.Items.Add(filename);
							}
						}
					}
				}
			}

			// Reset search
			FindPixTextBox.Text = "";
			FindRatingListBox.SelectedItem = null;
		}

		DataEntry GetDataEntry(string filename)
		{
			try
			{
				// Get Mesh objects
				var meshObjects = (from meshObject in mesh.CreateQuery<MeshObject>()
								   where meshObject.Resource.Type == LIVE_MESH_FOLDER
								   select meshObject);

				foreach (MeshObject meshObject in meshObjects)
				{
					// Get file data feed
					DataFeed theDataFeed = GetFileDataFeed(meshObject);

					if (theDataFeed != null)
					{
						// Get data entry containing file
						DataEntry theDataEntry = (from dataEntry in theDataFeed.CreateQuery<DataEntry>()
												  where dataEntry.Resource.Title == filename
												  select dataEntry).FirstOrDefault<DataEntry>();

						if (theDataEntry != null)
						{
							return theDataEntry;
						}
					}
				}

				return null;
			}
			catch (Exception ex)
			{
				MessageBox.Show("Caught exception looking for " + filename + ": " + ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return null;
			}
		}

		private void ShowPicButton_Click(object sender, EventArgs e)
		{
			// Clear the PictureBox control instance.
			ShowPictureBox.Image = null;

			if (FindPixListBox.SelectedItem == null)
			{
				MessageBox.Show("You must select a picture to show", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// Get data entry containing file
			// A real application would make sure this is a graphics file we can load
			string dataEntryName = FindPixListBox.SelectedItem.ToString();

			// Make sure this is a graphics file (this should never happen!)
			if (!IsGraphicsFile(dataEntryName))
			{
				MessageBox.Show("The file is not a graphics file!");
				return;
			}

			DataEntry dataentry = GetDataEntry(dataEntryName);

			if (dataentry == null)
			{
				MessageBox.Show("Problem getting " + dataEntryName, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
				return;
			}

			// If temp file exists, delete it
			if (!string.IsNullOrEmpty(tempFile))
			{
				try
				{
					GC.Collect();
					GC.WaitForPendingFinalizers();
					File.Delete(tempFile);
				}
				catch (Exception ex)
				{
					MessageBox.Show("Caught expection trying to delete " + tempFile +
					   Environment.NewLine + "   " + ex.Message +
					   Environment.NewLine + "You must delete it manually");
				}
			}

			// Create temp file
			Random random = new Random();
			int dummy = random.Next();

			tempFile = dummy.ToString();

			picStream = File.Create(tempFile);

			dataentry.ReadMediaResource(picStream);

			picStream.Flush();
			picStream.Close();
			picStream.Dispose();

			// Reset results list
			FindPixListBox.SelectedItem = null;

			ShowPic(tempFile);
		}

	}
}
